/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package moodlerest;

import java.io.*;
import java.net.*;
import java.util.Hashtable;
import java.util.Vector;
import java.util.logging.*;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Class containing the static routines to create, update and delete Moodle users.
 * @see MoodleUser
 * @author Bill Antonia
 */
public class MoodleRestUser {

    private static final int BUFFER_MAX = 4000;

    /**
     * Method to create a new user within Moodle from a MoodleUser object.
     * @param user MoodleUser with at least the username, password, lastname, firstname and email fields set
     * @return MoodleUser object updated with the user id within the Moodle site.
     * @throws MoodleRestUserException
     */
    public static MoodleUser createUser(MoodleUser user) throws MoodleRestUserException, UsuarioExistenteMoodleException, UnsupportedEncodingException {
        MoodleUser[] a = new MoodleUser[1];
        a[0] = user;
        MoodleUser[] usr = createUsers(a);
        return usr[0];
    }

    /**
     * Method to create new users within Moodle from an array of MoodleUser objects.
     * @param user MoodleUser[] array of MoodleUser with at least the username, password, lastname, firstname and email fields set.
     * @return MoodleUser[] array of MoodleUser objects updated with the user id within the Moodle site.
     * @throws MoodleRestUserException
     */
    public static MoodleUser[] createUsers(MoodleUser[] user) throws MoodleRestUserException, UsuarioExistenteMoodleException, UnsupportedEncodingException {
        Hashtable hash = new Hashtable();
        boolean processed = false;
        StringBuilder data = new StringBuilder();
        if (MoodleRestWebService.getAuth() == null) {
            throw new MoodleRestUserException();
        } else {
            data.append(MoodleRestWebService.getAuth());//data.append(URLEncoder.encode("wstoken", "UTF-8")).append("=").append(URLEncoder.encode(MoodleRestWebService.getToken(), "UTF-8"));
        }
        data.append("&").append(URLEncoder.encode("wsfunction", "UTF-8")).append("=").append(URLEncoder.encode("moodle_user_create_users", "UTF-8"));
        for (int i = 0; i < user.length; i++) {
            if (user[i] == null) {
                throw new MoodleRestUserException(MoodleRestUserException.USER_NULL);
            }
            if (user[i].getUsername() == null) {
                throw new MoodleRestUserException(MoodleRestUserException.USERNAME_NULL);
            } else {
                data.append("&").append(URLEncoder.encode("users[" + i + "][username]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getUsername(), "UTF-8"));
            }
            if (user[i].getPassword() == null) {
                throw new MoodleRestUserException(MoodleRestUserException.PASSWORD_NULL);
            } else {
                data.append("&").append(URLEncoder.encode("users[" + i + "][password]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getPassword(), "UTF-8"));
            }
            if (user[i].getFirstname() == null) {
                throw new MoodleRestUserException(MoodleRestUserException.FIRSTNAME_NULL);
            } else {
                data.append("&").append(URLEncoder.encode("users[" + i + "][firstname]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getFirstname(), "UTF-8"));
            }
            if (user[i].getLastname() == null) {
                throw new MoodleRestUserException(MoodleRestUserException.LASTNAME_NULL);
            } else {
                data.append("&").append(URLEncoder.encode("users[" + i + "][lastname]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getLastname(), "UTF-8"));
            }
            if (user[i].getEmail() == null) {
                throw new MoodleRestUserException(MoodleRestUserException.EMAIL_NULL);
            } else {
                data.append("&").append(URLEncoder.encode("users[" + i + "][email]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getEmail(), "UTF-8"));
            }
            if (user[i].getAuth() != null) {
                data.append("&").append(URLEncoder.encode("users[" + i + "][auth]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getAuth(), "UTF-8"));
            }
            if (user[i].getIdNumber() != null) {
                data.append("&").append(URLEncoder.encode("users[" + i + "][idnumber]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getIdNumber(), "UTF-8"));
            }
            if (user[i].getLang() != null) {
                data.append("&").append(URLEncoder.encode("users[" + i + "][lang]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getLang(), "UTF-8"));
            }
            if (user[i].getTheme() != null) {
                data.append("&").append(URLEncoder.encode("users[" + i + "][theme]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getTheme(), "UTF-8"));
            }
            if (user[i].getTimezone() != null) {
                data.append("&").append(URLEncoder.encode("users[" + i + "][timezone]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getTimezone(), "UTF-8"));
            }
            /*if (user[i].getMailFormat()!=-1) */ data.append("&").append(URLEncoder.encode("users[" + i + "][mailformat]", "UTF-8")).append("=").append(URLEncoder.encode("" + (user[i].getMailFormat() ? 1 : 0), "UTF-8"));
            if (user[i].getDescription() != null) {
                data.append("&").append(URLEncoder.encode("users[" + i + "][description]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getDescription(), "UTF-8"));
            }
            if (user[i].getCity() != null) {
                data.append("&").append(URLEncoder.encode("users[" + i + "][city]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getCity(), "UTF-8"));
            }
            if (user[i].getCountry() != null) {
                data.append("&").append(URLEncoder.encode("users[" + i + "][country]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getCountry(), "UTF-8"));
            }
            if (data.length() >= BUFFER_MAX) {
                processed = true;
                data.trimToSize();

                Document document = MoodleRestWebService.call(data.toString());
                NodeList elements = Util.getValueElementsFromXML(document);
                // Se não possui nós VALUE, então é uma Exception
                if (elements.getLength() == 0) {
                    throwUserException(document);
                }

                for (int j = 0; j < elements.getLength(); j += 2) {
                    hash.put(elements.item(j + 1).getTextContent(), elements.item(j).getTextContent());
                }

                data = new StringBuilder();
                data.append(MoodleRestWebService.getAuth());
                data.append("&").append(URLEncoder.encode("wsfunction", "UTF-8")).append("=").append(URLEncoder.encode("moodle_user_create_users", "UTF-8"));
            } else {
                processed = false;
            }
        }
        if (!processed) {
            data.trimToSize();
            Document document = MoodleRestWebService.call(data.toString());
            NodeList elements = Util.getValueElementsFromXML(document);
            // Se não possui nós VALUE, então é uma Exception
            if (elements.getLength() == 0) {
                throwUserException(document);
            }

            for (int j = 0; j < elements.getLength(); j += 2) {
                hash.put(elements.item(j + 1).getTextContent(), elements.item(j).getTextContent());
            }
        }

        for (int i = 0; i < user.length; i++) {
            user[i].setId(Long.parseLong((String) (hash.get(user[i].getUsername()))));
        }

        return user;
    }

    /**
     * Used to update the information for a single user within the Moodle site.
     * @param user MoodleUser object containing the updated user information.
     * @throws MoodleRestUserException
     */
    public static void updateUser(MoodleUser user) throws MoodleRestUserException {
        MoodleUser[] a = new MoodleUser[1];
        a[0] = user;
        updateUsers(a);
    }

    /**
     * Used to modify information about users within the Moodle site.
     * @param user MoodleUser[] array of MoodleUser objects containing the updated user information.
     * @throws MoodleRestUserException
     */
    public static void updateUsers(MoodleUser[] user) throws MoodleRestUserException {
        boolean processed = false;
        try {
            StringBuilder data = new StringBuilder();
            if (MoodleRestWebService.getAuth() == null) {
                throw new MoodleRestUserException();
            } else {
                data.append(MoodleRestWebService.getAuth());//data.append(URLEncoder.encode("wstoken", "UTF-8")).append("=").append(URLEncoder.encode(MoodleRestWebService.getToken(), "UTF-8"));
            }
            data.append("&").append(URLEncoder.encode("wsfunction", "UTF-8")).append("=").append(URLEncoder.encode("moodle_user_update_users", "UTF-8"));
            for (int i = 0; i < user.length; i++) {
                if (user[i] == null) {
                    throw new MoodleRestUserException(MoodleRestUserException.USER_NULL);
                }
                if (user[i].getId() == -1) {
                    throw new MoodleRestUserException(MoodleRestUserException.INVALID_USERID);
                } else {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][id]", "UTF-8")).append("=").append(URLEncoder.encode("" + user[i].getId(), "UTF-8"));
                }
                if (user[i].getUsername() != null) {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][username]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getUsername(), "UTF-8"));
                }
                if (user[i].getPassword() != null) {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][password]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getPassword(), "UTF-8"));
                }
                if (user[i].getFirstname() != null) {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][firstname]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getFirstname(), "UTF-8"));
                }
                if (user[i].getLastname() != null) {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][lastname]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getLastname(), "UTF-8"));
                }
                if (user[i].getEmail() != null) {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][email]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getEmail(), "UTF-8"));
                }
                if (user[i].getAuth() != null) {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][auth]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getAuth(), "UTF-8"));
                }
                if (user[i].getIdNumber() != null) {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][idnumber]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getIdNumber(), "UTF-8"));
                }
                if (user[i].getLang() != null) {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][lang]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getLang(), "UTF-8"));
                }
                if (user[i].getTheme() != null) {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][theme]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getTheme(), "UTF-8"));
                }
                if (user[i].getTimezone() != null) {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][timezone]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getTimezone(), "UTF-8"));
                }
                /*if (user[i].getMailFormat()!=-1) */ data.append("&").append(URLEncoder.encode("users[" + i + "][mailformat]", "UTF-8")).append("=").append(URLEncoder.encode("" + (user[i].getMailFormat() ? 1 : 0), "UTF-8"));
                if (user[i].getDescription() != null) {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][description]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getDescription(), "UTF-8"));
                }
                if (user[i].getCity() != null) {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][city]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getCity(), "UTF-8"));
                }
                if (user[i].getCountry() != null) {
                    data.append("&").append(URLEncoder.encode("users[" + i + "][country]", "UTF-8")).append("=").append(URLEncoder.encode(user[i].getCountry(), "UTF-8"));
                }
                if (data.length() >= BUFFER_MAX) {
                    processed = true;
                    data.trimToSize();
                    MoodleRestWebService.call(data.toString());
                    data = new StringBuilder();
                    data.append(MoodleRestWebService.getAuth());
                    data.append("&").append(URLEncoder.encode("wsfunction", "UTF-8")).append("=").append(URLEncoder.encode("moodle_user_update_users", "UTF-8"));
                } else {
                    processed = false;
                }
            }
            if (!processed) {
                data.trimToSize();
                MoodleRestWebService.call(data.toString());
            }
        } catch (IOException ex) {
            Logger.getLogger(MoodleRestUser.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * To delete the account of a single user within the Moodle site.
     * @param user long The Moodle id of the user to delete.
     * @throws MoodleRestUserException
     * @throws UnsupportedEncodingException
     */
    public static void deleteUser(long user) throws MoodleRestUserException, UnsupportedEncodingException, UsuarioExistenteMoodleException {
        long[] a = new long[1];
        a[0] = user;
        deleteUsers(a);
    }

    /**
     * Used to delete a number of users within the Moodle site.
     * @param userids long[] array of Moodle user ids
     * @throws MoodleRestUserException
     * @throws UnsupportedEncodingException
     */
    public static void deleteUsers(long[] userids) throws MoodleRestUserException, UnsupportedEncodingException, UsuarioExistenteMoodleException {
        boolean processed = false;
        try {
            StringBuilder data = new StringBuilder();
            if (MoodleRestWebService.getAuth() == null) {
                throw new MoodleRestUserException();
            } else {
                data.append(MoodleRestWebService.getAuth());//data.append(URLEncoder.encode("wstoken", "UTF-8")).append("=").append(URLEncoder.encode(MoodleRestWebService.getToken(), "UTF-8"));
            }
            data.append("&").append(URLEncoder.encode("wsfunction", "UTF-8")).append("=").append(URLEncoder.encode("moodle_user_delete_users", "UTF-8"));
            for (int i = 0; i < userids.length; i++) {
                if (userids[i] < 1) {
                    throw new MoodleRestUserException(MoodleRestUserException.INVALID_USERID);
                } else {
                    data.append("&").append(URLEncoder.encode("userids[" + i + "]", "UTF-8")).append("=").append(userids[i]);
                }
                if (data.length() >= BUFFER_MAX) {
                    processed = true;
                    data.trimToSize();
                    Document document = MoodleRestWebService.call(data.toString());
                    NodeList elements = Util.getValueElementsFromXML(document);
                    // Se não possui nós VALUE, então é uma Exception
                    if (elements.getLength() == 0) {
                        throwUserException(document);
                    }
                    data = new StringBuilder();
                    data.append(MoodleRestWebService.getAuth());
                    data.append("&").append(URLEncoder.encode("wsfunction", "UTF-8")).append("=").append(URLEncoder.encode("moodle_user_delete_users", "UTF-8"));
                } else {
                    processed = false;
                }
            }
            if (!processed) {
                data.trimToSize();
                MoodleRestWebService.call(data.toString());
            }
        } catch (IOException ex) {
            Logger.getLogger(MoodleRestUser.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Gets the information of a single users from their Moodle id
     * @param userid long Moodle id of the user
     * @return MoodleUser object containing the data of the selected user.
     * @throws MoodleRestUserException
     * @throws UnsupportedEncodingException
     */
    public static MoodleUser getUserById(long userid) throws MoodleRestUserException, UnsupportedEncodingException, UsuarioExistenteMoodleException {
        long[] a = new long[1];
        a[0] = userid;
        MoodleUser[] usr = getUsersById(a);
        return usr[0];
    }

    /**
     * Gets a number of MoodleUser objects containing the information of users from their Moodle ids
     * @param userids long[] array containing the Moodle ids of a number of users
     * @return MoodleUser[] array of MoodleUser objects containing the user data.
     * @throws MoodleRestUserException
     * @throws UnsupportedEncodingException
     */
    public static MoodleUser[] getUsersById(long[] userids) throws MoodleRestUserException, UnsupportedEncodingException, UsuarioExistenteMoodleException {
        Vector v = new Vector();
        MoodleUser user = null;
        boolean processed = false;
        try {
            StringBuilder data = new StringBuilder();
            if (MoodleRestWebService.getAuth() == null) {
                throw new MoodleRestUserException();
            } else {
                data.append(MoodleRestWebService.getAuth());//data.append(URLEncoder.encode("wstoken", "UTF-8")).append("=").append(URLEncoder.encode(MoodleRestWebService.getToken(), "UTF-8"));
            }
            data.append("&").append(URLEncoder.encode("wsfunction", "UTF-8")).append("=").append(URLEncoder.encode("moodle_user_get_users_by_id", "UTF-8"));
            for (int i = 0; i < userids.length; i++) {
                if (userids[i] < 1) {
                    throw new MoodleRestUserException(MoodleRestUserException.INVALID_USERID);
                }
                data.append("&").append(URLEncoder.encode("userids[" + i + "]", "UTF-8")).append("=").append(userids[i]);
                if (data.length() >= BUFFER_MAX) {
                    processed = true;
                    data.trimToSize();
                    Document document = MoodleRestWebService.call(data.toString());
                    NodeList elements = Util.getValueElementsFromXML(document);
                    // Se não possui nós VALUE, então é uma Exception
                    if (elements.getLength() == 0) {
                        throwUserException(document);
                    }
                    user = null;
                    for (int j = 0; j < elements.getLength(); j++) {
                        String content = elements.item(j).getTextContent();
                        String nodeName = elements.item(j).getParentNode().getAttributes().getNamedItem("name").getNodeValue();
                        if (nodeName.equals("id")) {
                            if (user == null) {
                                user = new MoodleUser(Long.parseLong(content));
                            } else {
                                v.add(user);
                                user = new MoodleUser(Long.parseLong(content));
                            }
                        }
                        user.setMoodleUserField(nodeName, content);
                    }
                    data = new StringBuilder();
                    data.append(MoodleRestWebService.getAuth());
                    data.append("&").append(URLEncoder.encode("wsfunction", "UTF-8")).append("=").append(URLEncoder.encode("moodle_user_get_users_by_id", "UTF-8"));
                } else {
                    processed = false;
                }
            }
            if (!processed) {
                data.trimToSize();
                Document document = MoodleRestWebService.call(data.toString());
                NodeList elements = Util.getValueElementsFromXML(document);
                // Se não possui nós VALUE, então é uma Exception
                if (elements.getLength() == 0) {
                    throwUserException(document);
                }
                user = null;
                for (int j = 0; j < elements.getLength(); j++) {
                    String content = elements.item(j).getTextContent();
                    String nodeName = elements.item(j).getParentNode().getAttributes().getNamedItem("name").getNodeValue();
                    if (nodeName.equals("id")) {
                        if (user == null) {
                            user = new MoodleUser(Long.parseLong(content));
                        } else {
                            v.add(user);
                            user = new MoodleUser(Long.parseLong(content));
                        }
                    }
                    user.setMoodleUserField(nodeName, content);
                }
            }
            if (user != null) {
                v.add(user);
            }
        } catch (IOException ex) {
            Logger.getLogger(MoodleRestUser.class.getName()).log(Level.SEVERE, null, ex);
        }
        MoodleUser[] users = new MoodleUser[v.size()];
        for (int i = 0; i < v.size(); i++) {
            users[i] = (MoodleUser) v.get(i);
        }
        v.removeAllElements();
        return users;
    }

    private static void throwUserException(Document document) throws UsuarioExistenteMoodleException {
        /* Exceções:
         * ==== USERS: =======
         * -Username already exists:
         * -Invalid authentication type:
         * -Invalid language code:
         * -Invalid theme:
         * -'Property: '.$key.' is too long:
         * ===================
         */
        NodeList elements = document.getElementsByTagName("DEBUGINFO");
        if (elements.getLength() == 1) {
            Node node = elements.item(0);
            //System.out.println(node.getTextContent());
            if (node.getTextContent().contains("Username already exists")) {
                String nomeUsuario = node.getTextContent().substring(node.getTextContent().lastIndexOf(":") + 1).trim();
                throw new UsuarioExistenteMoodleException(nomeUsuario);
            }
        }
    }
}
